package btree4j.template;

import btree4j.*;
import btree4j.indexer.BasicIndexQuery;
import btree4j.indexer.IndexQuery;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static btree4j.BTree.KEY_NOT_FOUND;

/**
 * 模板管理器，用于管理模板的创建、存储和检索
 */
public class TemplateManager {
    private BTreeIndex templateIndexer; // 模板索引器（模版id索引）
    private long nextTemplateId = 1; // 下一个模板 ID
    private File dataDir; // 数据目录
    private TemplateIndexManager indexManager; // 索引管理器
    private File lastTemplateIdFile; // 存储最后一个模板 ID 的文件
    private File availableIdsFile; // 存储可用 ID 的文件
    private List<Long> availableIds = new ArrayList<>(); // 可用 ID 列表

    private BTree nameIndexer; // 模板名二级索引


    public TemplateManager(File dataDir) throws IOException, BTreeException {
        this.dataDir = dataDir;
        this.lastTemplateIdFile = new File(dataDir, "last_template_id.txt");
        this.availableIdsFile = new File(dataDir, "available_ids.txt");
        if (!dataDir.exists()) {
            if (!dataDir.mkdirs()) {
                throw new IOException("Failed to create data directory: " + dataDir.getAbsolutePath());
            }
        }
        initTemplateIndex();
        indexManager = new TemplateIndexManager(dataDir, this);
        loadAvailableIds();
        loadLastTemplateId();
    }

    private void initTemplateIndex() throws IOException, BTreeException {
        File templateIndexFile = new File(dataDir, "template_index.idx");
        templateIndexer = new BTreeIndex(templateIndexFile);
        templateIndexer.init(/* bulkload */ false);

        // 初始化名称索引
        File nameIndexFile = new File(dataDir, "template_name_index.idx");
        nameIndexer = new BTreeIndex(nameIndexFile);
        nameIndexer.init(false);

        // 检查是否存在已有的模板数据
        if (templateIndexFile.exists()) {
            loadNextTemplateId();
        }
    }

    private void loadAvailableIds() {
        if (availableIdsFile.exists()) {
            try (BufferedReader reader = new BufferedReader(new FileReader(availableIdsFile))) {
                String idStr;
                while ((idStr = reader.readLine()) != null) {
                    availableIds.add(Long.parseLong(idStr));
                }
            } catch (IOException e) {
                throw new IllegalStateException("Failed to load available template IDs", e);
            }
        } else {
            // 如果文件不存在，尝试从索引中加载已有的模板 ID
            loadNextTemplateId();
        }
    }
    private void loadLastTemplateId() {
        if (lastTemplateIdFile.exists()) {
            try (BufferedReader reader = new BufferedReader(new FileReader(lastTemplateIdFile))) {
                String idStr = reader.readLine();
                if (idStr != null) {
                    nextTemplateId = Long.parseLong(idStr) + 1;
                }
            } catch (IOException e) {
                throw new IllegalStateException("Failed to load last template ID", e);
            }
        }
    }

    private void saveAvailableIds() {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(availableIdsFile))) {
            for (Long id : availableIds) {
                writer.write(String.valueOf(id));
                writer.newLine();
            }
        } catch (IOException e) {
            throw new IllegalStateException("Failed to save available template IDs", e);
        }
    }

    private void saveLastTemplateId(long id) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(lastTemplateIdFile))) {
            writer.write(String.valueOf(id));
        } catch (IOException e) {
            throw new IllegalStateException("Failed to save last template ID", e);
        }
    }

    private void loadNextTemplateId() {
        // 创建一个查询条件，假设模板的 ID 存储为键 "id"
        IndexQuery query = new BasicIndexQuery.IndexConditionEQ(new Value("id"));

        // 定义一个列表来存储查询结果中的 ID 值
        final List<Long> ids = new ArrayList<>();

        // 使用 BTreeIndex 的 search 方法进行查询，并传入一个回调对象
        try {
            templateIndexer.search(query, new BTreeCallback() {
                @Override
                public boolean indexInfo(Value key, long pointer) {
                    try {
                        // 从 Value 中获取字节数组
                        byte[] templateData = templateIndexer.retrieveTuple(pointer);
                        // 反序列化字节数组为 Template 对象
                        Template template = deserializeTemplate(templateData);
                        // 获取模板的 ID 并添加到列表中
                        if (template != null) {
                            ids.add(template.getId());
                        }
                    } catch (IOException e) {
                        throw new IllegalStateException("Failed to deserialize template", e);
                    } catch (BTreeException e) {
                        throw new RuntimeException(e);
                    }
                    return true;
                }

                @Override
                public boolean indexInfo(Value key, byte[] value) {
                    return false;
                }
            });
        } catch (BTreeException e) {
            throw new IllegalStateException("Failed to search template IDs", e);
        }

        // 如果查询到的 ID 列表不为空，找到最大的 ID 并加 1 作为下一个 ID
        if (!ids.isEmpty()) {
            nextTemplateId = Collections.max(ids) + 1;
        }

        // 保存最后一个使用的模板 ID
        if (!ids.isEmpty()) {
            saveLastTemplateId(Collections.max(ids));
        }
    }

    private Template deserializeTemplate(byte[] templateData) throws IOException {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(templateData);
             ObjectInputStream ois = new ObjectInputStream(bis)) {
            return (Template) ois.readObject();
        } catch (ClassNotFoundException e) {
            throw new IOException("Failed to deserialize template", e);
        }
    }

    public long createTemplate(Template template) throws IOException, BTreeException {
        long newId;
        if (!availableIds.isEmpty()) {
            newId = availableIds.remove(0);
        } else {
            newId = nextTemplateId++;
        }

        template.setId(newId);
        byte[] templateData;
        try {
            templateData = serializeTemplate(template);
        } catch (IOException e) {
            throw new IOException("Failed to serialize template", e);
        }
        try {
            long pointer = templateIndexer.addValue(new Value(template.getId()), new Value(templateData));
            if (pointer < 0) {
                throw new BTreeException("Failed to insert template into BTreeIndex");
            }
            templateIndexer.flush();

            // 创建模板的主键索引
            Column primaryKeyColumn = getPrimaryKeyColumn(template);
            if (primaryKeyColumn != null) {
                indexManager.createTemplateIndex(template.getId(), primaryKeyColumn.getName());
            }

            // 创建二级索引
            for (String indexedColumn : template.getIndexedColumns()) {
                indexManager.createTemplateIndex(template.getId(), indexedColumn);
            }

            // 保存最后一个使用的模板 ID
            saveLastTemplateId(template.getId());

            // 创建完成后，添加到名称索引
            Value nameKey = new Value(template.getName().getBytes(StandardCharsets.UTF_8));
            System.out.println("Adding template name index: key=" + template.getName() + ", value=" + template.getId());
            nameIndexer.addValue(nameKey, template.getId());
            nameIndexer.flush();

            return template.getId();
        } catch (BTreeException e) {
            throw new BTreeException("Failed to add template", e);
        }
    }

    private Column getPrimaryKeyColumn(Template template) {
        for (Column column : template.getColumns()) {
            if (column.isPrimaryKey()) {
                return column;
            }
        }
        return null;
    }

    private byte[] serializeTemplate(Template template) throws IOException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            oos.writeObject(template);
            return bos.toByteArray();
        }
    }

    public Template getTemplate(long templateId) throws IOException, BTreeException {
        if (templateIndexer == null) {
            throw new IllegalStateException("Template indexer is not initialized");
        }

        Value value = templateIndexer.getValue(new Value(templateId));
        if (value == null) {
            return null;
        }

        byte[] templateData = value.getData();
        if (templateData == null) {
            return null;
        }

        return deserializeTemplate(templateData);
    }

    public List<Template> getAllTemplates() {
        List<Template> allTemplates = new ArrayList<>();
        try {
            IndexQuery query = new BasicIndexQuery(BasicIndexQuery.ANY);
            templateIndexer.search(query, new BTreeCallback() {
                @Override
                public boolean indexInfo(Value key, long pointer) {
                    try {
                        byte[] templateData = templateIndexer.retrieveTuple(pointer);
                        Template template = deserializeTemplate(templateData);
                        if (template != null) {
                            allTemplates.add(template);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return true;
                }

                @Override
                public boolean indexInfo(Value key, byte[] value) {
                    try {
                        Template template = deserializeTemplate(value);
                        if (template != null) {
                            allTemplates.add(template);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return true;
                }
            });
        } catch (BTreeException e) {
            e.printStackTrace();
        }
        return allTemplates;
    }

    public Template getTemplateByName(String name) throws IOException, BTreeException {
        Value nameKey = new Value(name.getBytes(StandardCharsets.UTF_8));
        long templateId = nameIndexer.findValue(nameKey);
        if (templateId == KEY_NOT_FOUND) {
            return null;
        }
        return getTemplate(templateId);
    }

//    public void updateTemplate(Template template) throws IOException, BTreeException {
//        Template oldTemplate = getTemplate(template.getId());
//        if (oldTemplate != null && !oldTemplate.getName().equals(template.getName())) {
//            // 删除旧名称索引
//            Value oldNameKey = new Value(oldTemplate.getName().getBytes(StandardCharsets.UTF_8));
//            nameIndexer.removeValue(oldNameKey);
//            // 添加新名称索引
//            Value newNameKey = new Value(template.getName().getBytes(StandardCharsets.UTF_8));
//            nameIndexer.addValue(newNameKey, template.getId());
//        }
//        if (template == null) {
//            throw new IllegalArgumentException("Template cannot be null");
//        }
//
//        // Remove the old template
//        templateIndexer.removeValue(new Value(template.getId()));
//
//        // Create the updated template with the same ID
//        template.setId(template.getId()); // Ensure the ID remains the same
//        byte[] templateData;
//        try {
//            templateData = serializeTemplate(template);
//        } catch (IOException e) {
//            throw new IOException("Failed to serialize template", e);
//        }
//        try {
//            long pointer = templateIndexer.addValue(new Value(template.getId()), new Value(templateData));
//            if (pointer < 0) {
//                throw new BTreeException("Failed to insert template into BTreeIndex");
//            }
//
//            // 更新模板的主键索引（如果主键列发生变化）
//            Column primaryKeyColumn = getPrimaryKeyColumn(template);
//            if (primaryKeyColumn != null) {
//                indexManager.createTemplateIndex(template.getId(), primaryKeyColumn.getName());
//            }
//
//            templateIndexer.flush();
//            nameIndexer.flush();
//
//        } catch (BTreeException e) {
//            throw new BTreeException("Failed to update template", e);
//        }
//    }

    public void deleteTemplate(long templateId) throws IOException, BTreeException {
        Template template = getTemplate(templateId);
        if (template != null) {
            // 删除名称索引中的条目
            Value nameKey = new Value(template.getName().getBytes(StandardCharsets.UTF_8));
            nameIndexer.removeValue(nameKey);
        }
        nameIndexer.flush();
        try {
            // 获取模板的主键列名称
            String primaryKeyColumn = indexManager.getPrimaryKeyColumn(templateId);
            // 删除模板的主键索引
            indexManager.removeTemplateIndex(templateId, primaryKeyColumn);
            // 删除模板的索引条目
            templateIndexer.removeValue(new Value(templateId));
            templateIndexer.flush(); // Flush the index to ensure data consistency

            // 删除模板的二级索引
            for (String indexedColumn : template.getIndexedColumns()) {
                indexManager.removeTemplateIndex(templateId, indexedColumn);
            }
            // 将删除的 ID 添加到可用 ID 列表
            availableIds.add(templateId);
            saveAvailableIds();
        } catch (BTreeException e) {
            throw new BTreeException("Failed to delete template", e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public void deleteTemplateByName (String name) throws BTreeException, IOException {
        Value nameKey = new Value(name.getBytes(StandardCharsets.UTF_8));
        long templateId = nameIndexer.findValue(nameKey);
        if (templateId == KEY_NOT_FOUND) {
            System.out.println("Not Found!");
        }
        deleteTemplate(templateId);
    }


    public void addDataToTemplateIndex(long templateId, Value key, Value value) throws BTreeException, IOException {
        String primaryKeyColumn = indexManager.getPrimaryKeyColumn(templateId);
        indexManager.addDataToIndex(templateId,primaryKeyColumn, key, value);
    }

    public void updateDataInTemplateIndex(long templateId, Value key, Value newValue) throws BTreeException, IOException {
        String primaryKeyColumn = indexManager.getPrimaryKeyColumn(templateId);
        //indexManager.updateIndex(templateId, primaryKeyColumn, null, key, newValue);
        BTreeIndex primaryIndex = indexManager.getTemplateIndex(templateId, primaryKeyColumn);
        if (primaryIndex != null) {
            // 直接覆盖主键索引中的数据行值
            primaryIndex.putValue(key, newValue.getData());
            primaryIndex.flush();
        }
    }

    public void removeDataFromTemplateIndex(long templateId, Value key) throws BTreeException, IOException {
        String primaryKeyColumn = indexManager.getPrimaryKeyColumn(templateId); // 获取主键列名
        System.out.println(primaryKeyColumn);
        indexManager.removeDataFromIndex(templateId, primaryKeyColumn, key); // 添加列名参数
    }

    public Value getDataFromTemplateIndex(long templateId, Value key) throws BTreeException, IOException {
        String primaryKeyColumn = indexManager.getPrimaryKeyColumn(templateId); // 获取主键列名
        return indexManager.getDataFromIndex(templateId, primaryKeyColumn, key); // 添加列名参数
    }

    public void addDataToSecondaryIndex(long templateId, String columnName, Value key, Value primaryKey) throws BTreeException {
        indexManager.addDataToIndex(templateId, columnName, key, primaryKey);
    }

    public void updateSecondaryIndex(long templateId, String columnName, Value oldKey, Value newKey, Value primaryKey) throws BTreeException {
        indexManager.updateIndex(templateId, columnName, oldKey, newKey, primaryKey);
    }

    public void removeDataFromSecondaryIndex(long templateId, String columnName, Value key, long primaryKey) throws BTreeException {
        indexManager.removeDataFromIndex(templateId, columnName, key, primaryKey);
    }

    public List<Value> queryBySecondaryIndex(long templateId, String columnName, Value key) throws BTreeException {
        List<Value> results = new ArrayList<>();
        BTreeIndex index = indexManager.getTemplateIndex(templateId, columnName);
        if (index != null) {
            index.search(new BasicIndexQuery.IndexConditionEQ(key), new BTreeCallback() {
                @Override
                public boolean indexInfo(Value key, byte[] value) {
                    results.add(new Value(value));
                    return true;
                }

                @Override
                public boolean indexInfo(Value key, long pointer) {
                    try {
                        results.add(index.getValue(key));
                    } catch (BTreeException e) {
                        e.printStackTrace();
                    }
                    return true;
                }
            });
        }
        return results;
    }


    public void close() throws IOException, BTreeException {
        templateIndexer.close();
        nameIndexer.close();
    }
}